/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package espe.ccsoft.controllers;

import espe.ccsoft.dao.DespachoDao;
import espe.ccsoft.dao.EjecucionDao;
import espe.ccsoft.dao.FeriadoDao;
import espe.ccsoft.dao.PeriodoDao;
import espe.ccsoft.dao.RotacionDao;
import espe.ccsoft.dao.RutaDao;
import espe.ccsoft.dao.UnidadDao;
import espe.ccsoft.models.Ejecucion;
import espe.ccsoft.models.Feriados;
import espe.ccsoft.models.Periodo;
import espe.ccsoft.models.Rotacion;
import espe.ccsoft.models.Ruta;
import espe.ccsoft.models.Unidad;
import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

/**
 *
 * @author Carlos
 */
@ManagedBean
@RequestScoped
public class EjecucionController {

    private static List<Ejecucion> ejecuciones = new ArrayList<>();
    private static List<Rotacion> rotaciones = new ArrayList<>();
    private static List<Periodo> periodos = new ArrayList<>();

    private RutaDao rutaDao = new RutaDao();
    private PeriodoDao periodoDao = new PeriodoDao();
    private RotacionDao rotacionDao = new RotacionDao();
    private FeriadoDao feriadoDao = new FeriadoDao();
    private UnidadDao unidadDao = new UnidadDao();
    private EjecucionDao ejecucionDao = new EjecucionDao();
    private DespachoDao despachoDao = new DespachoDao();

    public RutaDao getRutaDao() {
        return rutaDao;
    }

    public void setRutaDao(RutaDao rutaDao) {
        this.rutaDao = rutaDao;
    }

    public List<Periodo> getPeriodos() {
        return periodos;
    }

    public static void setPeriodos(List<Periodo> periodos) {
        EjecucionController.periodos = periodos;
    }

    public List<Ejecucion> getEjecuciones() {
        return ejecuciones;
    }

    public void setEjecuciones(List<Ejecucion> ejecuciones) {
        EjecucionController.ejecuciones = ejecuciones;
    }

    public List<Ruta> getRutasDisponibles() throws Exception {
        return getRutaDao().findAll();
    }

    public String cargarHojaDeTrabajo(String ruta) throws Exception {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date dateWithoutTime = sdf.parse(sdf.format(calendar.getTime()));

        //Permite encontrar el id de la ruta dependiendo el dia
        String dia = tipoDia(dateWithoutTime);
        Ruta rutaTmp = rutaDao.findByNombreDia(ruta, dia);
        int numBuses = rutaTmp.getNumBuses();
        int numVueltas = 1;
        int count = 1;

        ejecuciones = ejecucionDao.findByDate(dateWithoutTime);
        for (Ejecucion aux : ejecuciones) {
            aux.setVuelta(numVueltas);
            if (count % numBuses == 0) {
                numVueltas += 1;
            }
            count++;
        }

        if (ejecuciones.size() == 0) {

            ejecuciones = new ArrayList<>();
            int countAux = 0;
            int numPeriodos = 0;
            int auxNumBuses = 0;

            Time t2 = Time.valueOf("00:00:00");
            long l2 = t2.getTime();

            Date horaInicial = new Date(l2);
            Date horaAux = null;

            rotaciones = rotacionDao.findByDate(dateWithoutTime);
            periodos = periodoDao.findAll(rutaTmp.getId());

            horaInicial = rutaTmp.getInicioHora();

            for (Periodo periodosTmp : periodos) {
                numPeriodos = this.getPeriodos().size();

                if (countAux == numPeriodos - 1) {
                    horaAux = new Date(rutaTmp.getFinHora().getTime());
                } else {
                    horaAux = this.getPeriodos().get(countAux + 1).getHora();
                }

                do {

                    Ejecucion ejecucion = new Ejecucion();                    
                    ejecucion.setNum(count);
                    ejecucion.setRutaId(rutaTmp.getId());
                    
                    ejecucion.setFecha(dateWithoutTime);
                    Unidad unidad = unidadDao.findByNumUnidad(rotaciones.get(auxNumBuses).getUnidad());
                    ejecucion.setHabilitacionProg(unidad.getHabilitacion());
                    ejecucion.setUnidadProg(unidad.getNumero());
                    ejecucion.setHoraInicioProg(horaInicial);
                    Date llegada = SumarHoras(horaInicial, periodosTmp.getCiclo());
                    ejecucion.setHoraFinProg(llegada);
                    ejecucion.setIntervalo(periodosTmp.getIntervalo());
                    ejecucion.setVuelta(numVueltas);
                    if (numVueltas == 1) {
                        ejecucion.setTiempoDespacho(new Date(l2));
                    } else {
                        ejecucion.setTiempoDespacho(restarHoras(horaInicial, ejecuciones.get(count - numBuses - 1).getHoraFinProg()));
                    }

                    auxNumBuses = auxNumBuses + 1;

                    if (count % numBuses == 0) {
                        numVueltas = numVueltas + 1;
                        auxNumBuses = 0;
                    }

                    if (count == 14) {
                        System.err.println("");
                    }

                    count = count + 1;
                    horaInicial = SumarHoras(horaInicial, periodosTmp.getIntervalo());
                    ejecucionDao.insert(ejecucion);
                    ejecuciones.add(ejecucion);

                } while (horaInicial.after(horaAux) != true);
            }
        }

        return "Ejecucion";
    }

    private int dayOfTheWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        int day = calendar.get(Calendar.DAY_OF_WEEK);
        return day;
    }

    private String tipoDia(Date date) {
        int numDia = dayOfTheWeek(date);
        if (numDia == 1) { //Domingo                     
            return "DOMINGO";
        } else if (numDia == 7 || fechaFeriado(date) == true) { //Sabado    
            return "SÁBADO";
        } else { //Ordinario
            return "ORDINARIO";
        }
    }

    private boolean fechaFeriado(Date fechaInicialTmp) {
        Feriados feriado = feriadoDao.findFeriado(fechaInicialTmp);
        return feriado != null;
    }

    private Date SumarHoras(Date fecha1, Date fecha2) {
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();

        calendar1.setTime(fecha1);
        calendar2.setTime(fecha2);

        calendar1.add(Calendar.HOUR_OF_DAY, calendar2.get(Calendar.HOUR_OF_DAY));
        calendar1.add(Calendar.MINUTE, calendar2.get(Calendar.MINUTE));
        return calendar1.getTime();
    }

    private Date restarHoras(Date fecha1, Date fecha2) {
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();

        calendar1.setTime(fecha1);
        calendar2.setTime(fecha2);

        calendar1.add(Calendar.HOUR_OF_DAY, -calendar2.get(Calendar.HOUR_OF_DAY));
        calendar1.add(Calendar.MINUTE, -calendar2.get(Calendar.MINUTE));
        return calendar1.getTime();
    }

    public void registrarHoraInicio(int num) throws ParseException, Exception {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm");
        Date time = sdf.parse(sdf.format(calendar.getTime()));
        ejecuciones.get(num - 1).setHoraInicioReal(time);
        ejecuciones.get(num - 1).setDespachoId(1);
        ejecucionDao.update(ejecuciones.get(num - 1));
    }

    public void registrarHoraLlegada(int num) throws ParseException, Exception {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm");
        Date time = sdf.parse(sdf.format(calendar.getTime()));
        ejecuciones.get(num - 1).setHoraFinReal(time);
        ejecuciones.get(num - 1).setDespachoId(1);
        ejecucionDao.update(ejecuciones.get(num - 1));
    }

}
